-
Notifications
You must be signed in to change notification settings - Fork 588
HDDS-14238. Move RDBBatchOperation Byte comparison to native comparison for optimization #9550
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
e4e5016 to
692b5ed
Compare
a3349d7 to
deb7900
Compare
…on for optimization Change-Id: Ia7655ff5148197be488a2c1151ec7fd1d6f9d452
deb7900 to
72c13eb
Compare
|
@szetszwo This is good to be reviewed. I will click on ready for review when I get a +1. I don't want to run the CI multiple times. |
szetszwo
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@swamirishi , thanks for working on this! Please see the comments inlined.
| private void initWithByteArray(byte[] array) { | ||
| this.slice = new ManagedSlice(array); | ||
| this.hash = ByteBuffer.wrap(array).hashCode(); | ||
| } | ||
|
|
||
| ByteBuffer asReadOnlyByteBuffer() { | ||
| return buffer.asReadOnlyByteBuffer(); | ||
| private void initWithDirectByteBuffer(ByteBuffer byteBuffer) { | ||
| this.slice = new ManagedDirectSlice(byteBuffer); | ||
| this.hash = byteBuffer.hashCode(); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Constructors should not call any functions. Otherwise, the fields cannot be final, which is very useful for reducing bugs and for understanding the code..
private final AbstractSlice<?> slice;
/** Cache the hash value. */
private final int hash;
static Bytes newBytes(CodecBuffer buffer) {
Objects.requireNonNull(buffer, "buffer == null");
return buffer.isDirect() ? new Bytes(buffer.asReadOnlyByteBuffer()) : new Bytes(buffer.getArray());
}
Bytes(ByteBuffer buffer) {
Objects.requireNonNull(buffer, "buffer == null");
assertTrue(buffer.isDirect(), "buffer is not direct");
this.slice = new ManagedDirectSlice(buffer);
this.hash = buffer.hashCode();
}
Bytes(byte[] array) {
Objects.requireNonNull(array, "array == null");
this.slice = new ManagedSlice(array);
this.hash = ByteBuffer.wrap(array).hashCode();
}There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
| public String toString() { | ||
| return array != null ? bytes2String(array) | ||
| : bytes2String(asReadOnlyByteBuffer()); | ||
| return slice.toString(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Have you checked what will it return? Could you show an example output?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
public static void main(String[] args) throws CodecException {
String value = "test";
Bytes bytes = new Bytes(value.getBytes(UTF_8));
System.out.println("To String Heap Value: " + bytes);
Bytes dbytes = newBytes(CodecBufferCodec.get(true).fromPersistedFormat(value.getBytes(UTF_8)));
System.out.println("To String Direct Value: " + dbytes);
}
2025-12-28 18:25:34,786 [main] INFO db.CodecBuffer (CodecBuffer.java:set(85)) - Successfully set constructor to LeakDetector::newCodecBuffer: org.apache.hadoop.hdds.utils.db.CodecBuffer$$Lambda$4/1694556038@7085bdee
To String Heap Value: test
To String Direct Value: test
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To String Heap Value: test
To String Direct Value: test
Isn't the data supposed to be binary? This seems not working.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is supposed to be the char decoded value. https://github.com/facebook/rocksdb/blob/1cfdece85ddc9450d24c3007222195e46e1cc0a8/util/slice.cc#L303-L304
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When you say it is not working. Maybe you are not loading the rocksdb libs before this. I forgot there was static codeblock loading the rocksdb lib.
This should work:
public static void main(String[] args) throws CodecException {
ManagedRocksObjectUtils.loadRocksDBLibrary();
String value = "test";
Bytes bytes = new Bytes(value.getBytes(UTF_8));
System.out.println("To String Heap Value: " + bytes);
Bytes dbytes = newBytes(CodecBufferCodec.get(true).fromPersistedFormat(value.getBytes(UTF_8)));
System.out.println("To String Direct Value: " + dbytes);
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The output before the change and after will be the same since StringUtils.byte2String() also decodes the byte value to String value
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we want the binary value then we have to print the hex value.
slice.toString(true) would do that
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I did the above to keep the behaviour same as before.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You are right -- it is the same as before.
| assertEquals(fromArray.hashCode(), fromBuffer.hashCode()); | ||
| assertEquals(fromArray, fromBuffer); | ||
| assertEquals(fromBuffer, fromArray); | ||
| for (CodecBuffer.Allocator allocator : ImmutableList.of(CodecBuffer.Allocator.HEAP, CodecBuffer.Allocator.DIRECT)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pass allocator instead of adding a loop.
runTestBytes(original, codec, CodecBuffer.Allocator.HEAP);
runTestBytes(original, codec, CodecBuffer.Allocator.DIRECT);
}
static <T> void runTestBytes(T object, Codec<T> codec, CodecBuffer.Allocator allocator) throws IOException {
final byte[] array = codec.toPersistedFormat(object);
final Bytes fromArray = new Bytes(array);
try (CodecBuffer buffer = codec.toCodecBuffer(object, allocator)) {There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
@swamirishi , we should pass the CI first before asking for reviewing -- if the change cannot pass CI, it may be fundamentally incorrect. What is the point for reviewing? |
Change-Id: I913be571b87e318abc798c7396ca072de23b01e8
One can always check the CI run on the fork. We have been following this model on almost all PRs for a while. |
Please provide the link then. I would like to save my time for finding it. |
https://github.com/swamirishi/ozone/actions/runs/20561058088 |
|
@szetszwo i have addressed all your review comments is this good to be merged? |
szetszwo
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@swamirishi , thanks for the update! Please see the comment inlined.
| public String toString() { | ||
| return array != null ? bytes2String(array) | ||
| : bytes2String(asReadOnlyByteBuffer()); | ||
| return slice.toString(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To String Heap Value: test
To String Direct Value: test
Isn't the data supposed to be binary? This seems not working.
szetszwo
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1 the change looks good.
|
Thank you @szetszwo for reviewing the patch |
What changes were proposed in this pull request?
Instead of performing ByteWise comparison on Java side moving the comparison to native side would more optimal since most of the transactions are going to use direct byte buffers. Here we intend to use the rocksdb Slice to perform bytewise comparisons. RocksDB Bytewise comparators also uses the same comparator.
https://github.com/facebook/rocksdb/blob/c110091d368b8a01b5be36a14198769e60786c05/util/comparator.cc#L36-L38
Unfortunately currently in 7.7.3 there is no direct native comparison that has been implemented. We can look into contributing to Rocksdb by having a JNI implementation for
https://github.com/facebook/rocksdb/blob/0bf9079d44eea91afda7151306d3a3439a39511b/java/src/main/java/org/rocksdb/NativeComparatorWrapper.java#L16
Till then this is a nice workaround to have.
What is the link to the Apache JIRA
https://issues.apache.org/jira/browse/HDDS-14238
How was this patch tested?
Update existing unit tests